﻿namespace ReplayDataFile
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    public class BlockFile
    {
        public BlockAllocateTable BlockAllocTable;
        protected string fileName;
        internal FileStream fStream;
        protected int ignoreTimebackSeconds = 60;
        protected bool isOpened = false;
        protected Dictionary<int, RecordConvertProc> recordConvertDict = new Dictionary<int, RecordConvertProc>();

        public BlockFile(string fileName)
        {
            this.fileName = fileName;
            this.Header = new BlockFileHeader();
            this.DataTypeDir = new DataTypeDirectory(0, null);
            this.BlockAllocTable = new BlockAllocateTable(0);
        }

        public virtual bool Close()
        {
            lock (this)
            {
                if (this.fStream != null)
                {
                    this.fStream.Close();
                    this.fStream = null;
                }
                this.isOpened = false;
            }
            return true;
        }

        protected long GetDataBlockInFileOffset(int blockIndex)
        {
            return (((BlockFileHeader.Size + this.BlockAllocTable.Size) + this.DataTypeDir.Size) + (this.Header.BlockSize * blockIndex));
        }

        public void GetDataTimeRange(out DateTime beginTime, out DateTime endTime)
        {
            beginTime = DateTime.MaxValue;
            endTime = DateTime.MinValue;
            foreach (TimeSegment segment in this.Header.TimeSegments)
            {
                if (segment.BeginTime < beginTime)
                {
                    beginTime = segment.BeginTime;
                }
                if (segment.EndTime > endTime)
                {
                    endTime = segment.EndTime;
                }
            }
            if (beginTime == DateTime.MaxValue)
            {
                beginTime = DateTime.MinValue;
            }
        }

        public int GetDataTypeId(string dataTypeName)
        {
            DataTypeDirEntry dirEntry = this.DataTypeDir.GetDirEntry(dataTypeName);
            if (dirEntry == null)
            {
                return 0;
            }
            return dirEntry.DataType;
        }

        public string GetDataTypeName(int dataType)
        {
            DataTypeDirEntry dirEntry = this.DataTypeDir.GetDirEntry(dataType);
            if (dirEntry == null)
            {
                return "";
            }
            return dirEntry.Name;
        }

        private static long GetOverlapTime(DateTime begin1, DateTime end1, DateTime begin2, DateTime end2)
        {
            if ((begin1 > end2) || (begin2 > end1))
            {
                return 0L;
            }
            DateTime time = (begin1 > begin2) ? begin1 : begin2;
            DateTime time2 = (end1 > end2) ? end2 : end1;
            TimeSpan span = (TimeSpan) (time2 - time);
            return span.Ticks;
        }

        public bool IsContainData(DateTime beginTime, DateTime endTime)
        {
            if (beginTime == endTime)
            {
                endTime = beginTime.AddTicks(1L);
            }
            foreach (TimeSegment segment in this.Header.TimeSegments)
            {
                if (GetOverlapTime(beginTime, endTime, segment.BeginTime, segment.EndTime.AddSeconds(1.0)) > 0L)
                {
                    return true;
                }
            }
            return false;
        }

        public virtual bool Open()
        {
            return this.OpenExist(FileAccess.Read, FileShare.ReadWrite);
        }

        protected bool OpenExist(FileAccess fileAccess, FileShare fileShare)
        {
            if (!File.Exists(this.fileName))
            {
                return false;
            }
            FileInfo info = new FileInfo(this.fileName);
            this.FileSize = info.Length;
            if (this.FileSize < BlockFileHeader.Size)
            {
                return false;
            }
            this.fStream = new FileStream(this.fileName, FileMode.Open, fileAccess, fileShare);
            this.fStream.Seek(0L, SeekOrigin.Begin);
            byte[] buffer = new byte[BlockFileHeader.Size];
            this.fStream.Read(buffer, 0, buffer.Length);
            if (!this.Header.FromByteBuffer(buffer))
            {
                this.fStream.Close();
                return false;
            }
            long num = (BlockFileHeader.Size + this.Header.DataTypeDirSize) + this.Header.BlockAllocTableSize;
            if (this.FileSize < num)
            {
                return false;
            }
            DataTypeInfo[] dataTypes = this.DataTypeDir.GetDataTypes();
            buffer = new byte[this.Header.DataTypeDirSize];
            this.fStream.Read(buffer, 0, buffer.Length);
            if (!this.DataTypeDir.FromByteBuffer(buffer))
            {
                this.fStream.Close();
                return false;
            }
            foreach (DataTypeInfo info2 in dataTypes)
            {
                this.DataTypeDir.AddDataType(info2);
            }
            buffer = new byte[this.Header.BlockAllocTableSize];
            this.fStream.Read(buffer, 0, buffer.Length);
            if (!this.BlockAllocTable.FromByteBuffer(buffer))
            {
                this.fStream.Close();
                return false;
            }
            foreach (DataTypeDirEntry entry in this.DataTypeDir.DirEntries)
            {
                entry.CurDataBlock = this.BlockAllocTable.GetLastAllocBlock(entry.FirstDataBlock);
                entry.CurIndexBlock = this.BlockAllocTable.GetLastAllocBlock(entry.FirstIndexBlock);
            }
            return true;
        }

        public bool RegRecordConvertProc(int dataType, RecordConvertProc proc)
        {
            if (this.recordConvertDict.ContainsKey(dataType))
            {
                return false;
            }
            this.recordConvertDict.Add(dataType, proc);
            return true;
        }

        public bool SetDataTypeName(int dataType, string name)
        {
            DataTypeDirEntry dirEntry = this.DataTypeDir.GetDirEntry(dataType);
            if (dirEntry == null)
            {
                return false;
            }
            dirEntry.Name = name;
            return true;
        }

        public DataTypeDirectory DataTypeDir { get; set; }

        public string FileName
        {
            get
            {
                return this.fileName;
            }
        }

        public long FileSize { get; set; }

        public BlockFileHeader Header { get; set; }

        public TimeSegment LastTimeSegment
        {
            get
            {
                if (this.Header.TimeSegments.Count > 0)
                {
                    return this.Header.TimeSegments[this.Header.TimeSegments.Count - 1];
                }
                return null;
            }
        }
    }
}

